package com.violet.swagger;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.SpecVersion;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 类说明: swagger 配置类
 *
 * @author wqf
 * @date 2022/7/26 10:23
 */
@Configuration
public class SwaggerAutoConfiguration {

    private static final String AUTH_KEY = "Authorization";


    @Bean
    @ConditionalOnMissingBean
    public SwaggerProperties swaggerProperties() {
        return new SwaggerProperties();
    }




    /**
     * 创建 Info对象
     *
     * @param swaggerProperties swagger配置
     * @return Info
     */
    @Bean
    public OpenAPI customOpenAPI(SwaggerProperties swaggerProperties) {

        Info info = new Info()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .license(new License()
                        .name(swaggerProperties.getLicenseName())
                        .url(swaggerProperties.getLicenseUrl()))
                .contact(new Contact()
                        .name(swaggerProperties.getContact().getName())
                        .url(swaggerProperties.getContact().getUrl())
                        .email(swaggerProperties.getContact().getEmail())
                )
                .termsOfService(swaggerProperties.getTermsOfServiceUrl());

        return new OpenAPI(SpecVersion.V30)
                .addSecurityItem(securityContexts())
                .components(components(swaggerProperties))
                .info(info);
    }


    private SecurityRequirement securityContexts() {
        SecurityRequirement securityRequirement = new SecurityRequirement();
        securityRequirement.addList(HttpHeaders.AUTHORIZATION);
        return securityRequirement;
    }

    private Components components(SwaggerProperties swaggerProperties) {
        Components components = new Components();
        //构建请求头参数
        List<Parameter> parameters = parameters(swaggerProperties.getGlobalOperationParameters());
        if (!parameters.isEmpty()) {
            for (Parameter parameter : parameters) {
                components.addParameters(parameter.getName(), parameter);
            }
        }
        SecurityScheme securityScheme = new SecurityScheme()
                .name(HttpHeaders.AUTHORIZATION)
                .type(SecurityScheme.Type.HTTP)
                .in(SecurityScheme.In.HEADER)
                .bearerFormat("JWT")
                .scheme("bearer ");

        components.addSecuritySchemes(HttpHeaders.AUTHORIZATION, securityScheme);
        return components;
    }

    @Bean
    public GroupedOpenApi userApi() {
        String[] paths = {"/**"};
        String[] packagedToMatch = {"com.violet"};
        return GroupedOpenApi.builder()
                .group("default")
                .packagesToScan(packagedToMatch)
                .pathsToMatch(paths)
                .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Operation.class))
                .addOperationCustomizer((operation, handlerMethod) -> operation.addParametersItem(
                                new HeaderParameter()
                                        .name("groupCode")
                                        .example("测试")
                                        .description("集团code")
                                        .schema(new StringSchema())
                                        .in("header")
                                        .required(true)
                                        .allowEmptyValue(false)
                        )
                )
                .build();
    }

    /**
     * 认证的安全上下文
     *
     * @return
     */
    private List<SecurityScheme> securitySchemes() {
        List<SecurityScheme> apiKeys = new ArrayList<>(1);
        SecurityScheme securityScheme = new SecurityScheme()
                .type(SecurityScheme.Type.APIKEY)
                // 这里配置 bearer 后，你的请求里会自动在 token 前加上 Bearer
                .scheme(AUTH_KEY)
                .bearerFormat(AUTH_KEY);
        apiKeys.add(securityScheme);
        return apiKeys;
    }

    /**
     * 构建请求头参数 生成swagger全局通用参数 如：请求token
     */
    private List<Parameter> parameters(
            List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters) {

        List<Parameter> parameters = new ArrayList<>();
        if (Objects.isNull(globalOperationParameters)) {
            return parameters;
        }
        for (SwaggerProperties.GlobalOperationParameter globalOperationParameter : globalOperationParameters) {
            parameters.add(new Parameter()
                    //参数名称
                    .name(globalOperationParameter.getName())
                    //参数说明
                    .description(globalOperationParameter.getDescription())
                    //参数存放位置
                    .in(globalOperationParameter.getParameterType())
                    //参数数据类型 暂时写死为string 有其他需求再改
                    .schema(new StringSchema())
                    //参数是否必须
                    .required(Boolean.parseBoolean(globalOperationParameter.getRequired()))
                    //是否允许为空
                    .allowEmptyValue(globalOperationParameter.isAllowEmptyValue())
            );

        }
        return parameters;
    }


}